Created by miccall (转载请注明出处 miccall.tech)
基于substance painter 2018.2.3
入口 :
substance 的 shader 用的就是普通的 glsl 文件 ,导入直接拖进去就ok 。
但是写法还有有一定的区别 。
我们随便新建一个 glsl :
void shade(V2F inputs) {
diffuseShadingOutput(vec3(1.0, 0.0, 1.0));
}
这个就是我们的入口函数,直接返回一个值 。
在substance painter 里面,直接设置这个shader就可以看到效果了 。
V2F和unity 差不多 ,就是 vertex 到 fragment 的 结构体 ,只是 substance 不允许我们写 vert shader
struct V2F {
vec3 normal; // interpolated normal
vec3 tangent; // interpolated tangent
vec3 bitangent; // interpolated bitangent
vec3 position; // interpolated position
vec4 color[1]; // interpolated vertex colors (color0)
vec2 tex_coord; // interpolated texture coordinates (uv0)
vec2 multi_tex_coord[8]; // interpolated texture coordinates (uv0-uv7)
};
基本上我们要的东西都有了 。
输出也有一定的规范 ,以前的版本是
return emissiveColor + albedo * diffuseShading + specularShading
但是现在 sp 把 几者都分开了 ,我们只能按照通道返回相应的值:
// fragment opacity. default value: 1.0
void alphaOutput(float);
// diffuse lighting contribution. default value: vec3(0.0)
void diffuseShadingOutput(vec3);
// specular lighting contribution. default value: vec3(0.0)
void specularShadingOutput(vec3);
// color emitted by the fragment. default value: vec3(0.0)
void emissiveColorOutput(vec3);
// fragment color. default value: vec3(1.0)
void albedoOutput(vec3);
// subsurface scattering properties, see lib-sss.glsl for details. default value: vec4(0.0)
void sssCoefficientsOutput(vec4);
除了基本的输入输出通道,我们还有其他的一些资源可以使用 :
//:param auto TEXTURE_TAG
uniform sampler2D uniform_tex ; //纹理本身
//:param auto TEXTURE_TAG_is_set
uniform bool uniform_tex_is_set ; //一个布尔值,指示纹理是否在文档中
//:param auto TEXTURE_TAG_size
uniform vec4 uniform_tex_size ; //纹理的大小(宽度,高度,1 /宽度,1 /高度)
等等还有很多贴图 ,具体可以参考帮助文档 。
在 substance painter 中 ,//: 后面的不是注释,而是 一种参数配置
这种定制方法使我们可以自定义数据类型
// 定义一个 RGB的 color 默认值为 0
//: param custom { "default": 0, "label": "Color RGB", "widget": "color" }
uniform vec3 u_color_float3;
// 定义一个 RGBA 的 color 默认值为 1
//: param custom { "default": 1, "label": "Color RGBA", "widget": "color" }
uniform vec4 u_color_float4;
// 当然,label 还有 Int spinbox,
// "Int slider", "min": 0, "max": 10
// 等等 。。。
除了基本变量 ,substance painter 还给我们定制了一些 function
用的时候直接 import :
lib-alpha.glsl:包含不透明度相关的
lib-bayer.glsl:包含拜耳矩阵
lib-defines.glsl:包含有用的数学常量
lib-emissive.glsl:包含自发光属性
lib-env.glsl:包含与环境贴图相关的帮助程序
lib-normal.glsl:包含与法线相关的(以及高度图生成的法线贴图)
lib-pbr.glsl:包含基于物理的渲染
lib-pom.glsl:包含视差遮挡映射
lib-random.glsl:包含随机实用程序(hammersley序列)
lib-sampler.glsl:包含channel getters
lib-sss.glsl:包含次表面散射
lib-utils.glsl:包含颜色实用程序函数(sRGB转换,色调映射)
lib-vectors.glsl:包含常见的向量
// api 和源码都有
默认材质 pbr-metal-rough
void shade(V2F inputs)
{
// Apply parallax occlusion mapping if possible
vec3 viewTS = worldSpaceToTangentSpace(getEyeVec(inputs.position), inputs);
inputs.tex_coord += getParallaxOffset(inputs.tex_coord, viewTS);
// Fetch material parameters, and conversion to the specular/roughness model
float roughness = getRoughness(roughness_tex, inputs.tex_coord);
vec3 baseColor = getBaseColor(basecolor_tex, inputs.tex_coord);
float metallic = getMetallic(metallic_tex, inputs.tex_coord);
float specularLevel = getSpecularLevel(specularlevel_tex, inputs.tex_coord);
vec3 diffColor = generateDiffuseColor(baseColor, metallic);
vec3 specColor = generateSpecularColor(specularLevel, baseColor, metallic);
// Get detail (ambient occlusion) and global (shadow) occlusion factors
float occlusion = getAO(inputs.tex_coord) * getShadowFactor();
float specOcclusion = specularOcclusionCorrection(occlusion, metallic, roughness);
LocalVectors vectors = computeLocalFrame(inputs);
// Feed parameters for a physically based BRDF integration
emissiveColorOutput(pbrComputeEmissive(emissive_tex, inputs.tex_coord));
albedoOutput(diffColor);
diffuseShadingOutput(occlusion * envIrradiance(vectors.normal));
specularShadingOutput(specOcclusion * pbrComputeSpecular(vectors, specColor, roughness));
sssCoefficientsOutput(getSSSCoefficients(inputs.tex_coord));
}
更改我们的shader ,支持各向异性 头发 :
我们只需更改高光部分就ok :
specularShadingOutput(specOcclusion * HairSpecular(vectors, specColor, roughness));
这个方法是我们自定义的方法 :
vec3 ShiftTangent ( vec3 T, vec3 N)
{
return normalize(T + _shift * N);
}
vec3 HairSpecular(LocalVectors vectors, vec3 specColor, float roughness)
{
vec3 radiance = vec3(0.0);
float ndv = dot(vectors.eye, vectors.normal);
vec3 T = ShiftTangent(vectors.bitangent,vectors.normal);
vec3 H = normalize(lightDirection + vectors.eye);
float dotTH = dot(T, H);
float sinTH = sqrt(1 - dotTH * dotTH);
float dirAtten = smoothstep(-1, 0, dotTH);
radiance = vec3(dirAtten * pow(sinTH, 100.0)) * specColor ;
return radiance;
}
default :
custom :
这是一个极其简化的公式 ,到时候会研究一下substance painter 的BRDF 公式 ,他似乎对每一项都进行了循环采样,使得效果不是unity和unreal 可以比拟的。
所以很多美术吐槽在substance里面效果很好,为什么到了引擎里面折扣这么大 。